home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stream.h>
- #include <string.h>
- #include "sw.h"
- #include "extern.h"
- #include "main.h"
- #include "ship.h"
- #include "control.h"
- #include "resources.h"
- #include "sound.h"
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <errno.h>
- // ADDED 08/11/93:
- #include <CC/osfcn.h>
-
- //
- // Broadcast communication stuff
- //
-
- static int infoSocket;
- static struct sockaddr_in infoAddr;
-
- int openBroadcast(int port)
- {
- infoSocket = openBroadcastSocket(port, &infoAddr);
- return (infoSocket != -1);
- }
-
- void closeBroadcast()
- {
- close(infoSocket);
- }
-
- int sendBroadcast(const ShipInfo& si)
- {
- BroadcastPacket p;
- p.serverId = server()->serverId();
- p.length = sizeof(si);
- p.message = si;
-
- return (sendto(infoSocket, (void*)&p, sizeof(p), 0, &infoAddr,
- sizeof(infoAddr)) == sizeof(p));
- }
-
- int recvBroadcast(ShipInfo& si)
- {
- BroadcastPacket p;
- struct sockaddr_in from;
- int fromlen;
- int c;
-
- do {
- fromlen = sizeof(from);
- c = recvfrom(infoSocket, (void*)&p, sizeof(p), 0, &from, &fromlen);
- if (c < 0) { // error getting message
- if (errno == EWOULDBLOCK) // don't worry about it
- return FALSE;
- else {
- perror("recvbroadcast");
- return FALSE;
- }
- }
- if (c == 0) return FALSE; // no message
- } while (NetId(from.sin_addr) == server()->hostId() ||
- NetId(p.serverId) != server()->serverId());
- si = p.message;
-
- return TRUE;
- }
-
- void handleBroadcastMessages()
- {
- ShipInfo si;
- while (recvBroadcast(si)) {
- ShipObject* s = getPlayer(lookupPlayer(NetId(si.myId)));
- if (self(s)) continue; // ignore my messages
- s->read(si);
- }
- }
-
- //
- // Server message handling
- //
-
- void handleServerMessages()
- {
- const SwAnyMessage* any;
- while (server()->receive() != SwNone) {
- any = server()->get();
- switch (server()->type()) {
- case SwAddPlayer: {
- const SwAddPlayerMessage* m =
- (const SwAddPlayerMessage*)&(any->addPlayer);
- if (self(m->p.id)) break; // don't add myself
- ShipObject* n = makeShip(m->p.shipClass,(InAddr &)m->p.id, m->p.team, m->p.name);
- n->reset();
- addPlayer(n);
- break;
- }
- case SwRemovePlayer: {
- const SwRemovePlayerMessage* m =
- (const SwRemovePlayerMessage*)&(any->removePlayer);
- int p = lookupPlayer((InAddr &)m->id);
- ShipObject* s = getPlayer(p);
- if (s && !self(s)) // don't remove unknown or me
- removePlayer(p);
- break;
- }
- case SwFlagUpdate: {
- const SwFlagUpdateMessage* m =
- (const SwFlagUpdateMessage*)&(any->flagUpdate);
- setTeam(m->info);
- break;
- }
- case SwFlagGrabbed: {
- const SwFlagGrabbedMessage* m =
- (const SwFlagGrabbedMessage*)&(any->flagGrabbed);
- ShipObject* s = getPlayer(lookupPlayer(NetId((InAddr &)m->grabber)));
- setTeam(m->info);
- if (m->info.team == myShip->team() && m->info.state == FlagOnShip) {
- if (s) {
- if (s->team() != myShip->team()) // enemy has my flag!
- soundPlay(EnemyGrabSound);
- }
- else {
- // dunno, unknown person has my flag! what to do?
- }
- }
- if (self(s)) { // I grabbed flag
- s->flag(m->info.team);
- flagChanged();
- server()->send("grabbed %s flag", s->flag());
- soundPlay(GrabSound);
- }
- break;
- }
- case SwFlagDropped: {
- const SwFlagDroppedMessage* m =
- (const SwFlagDroppedMessage*)&(any->flagDropped);
- ShipObject* s = getPlayer(lookupPlayer(NetId((InAddr&)m->dropper)));
- setTeam(m->info);
- if (self(s)) { // I grabbed flag
- server()->send("dropped %s flag", m->info.team);
- s->flag(NoTeam);
- flagChanged();
- soundPlay(DropSound);
- }
- break;
- }
- case SwFlagCaptured: {
- const SwFlagCapturedMessage* m =
- (const SwFlagCapturedMessage*)&(any->flagCaptured);
- setTeam(m->flagTeam);
- setTeam(m->captorTeam);
- int lost = (m->flagTeam.team == myShip->team()),
- won = (m->captorTeam.team == myShip->team() &&
- myShip->flag() == m->flagTeam.team);
- if (lost) { // my flag captured
- wasFlagCaptured = TRUE;
- if (won) { // took my flag into enemy base
- server()->send("took my flag into enemy base");
- myShip->flag(NoTeam);
- flagChanged();
- }
- myShip->explodeShip(NetId()); // I'm dead -- no killer
- soundPlay(FlagLostSound);
- }
- else if (won) { // I captured it
- server()->send("captured %s flag", myShip->flag());
- myShip->flag(NoTeam);
- flagChanged();
- soundPlay(FlagWonSound);
- }
- scoreChanged();
- break;
- }
- case SwHit: {
- const SwHitMessage* m = (const SwHitMessage*)&(any->hit);
- if (self(m->victim)) { // hit me or mine
- if (m->missileNum == -1) // hit ship
- myShip->hitShield(*m);
- else // hit missile
- myShip->explodeMissile(*m);
- }
- break;
- }
- case SwKilled: {
- const SwKilledMessage* m = (const SwKilledMessage*)&(any->killed);
- if (self(m->killer)) { // I did killing
- if (self(m->victim)) // I killed myself
- server()->send("blew myself up");
- else {
- ShipObject* v = getPlayer(lookupPlayer(NetId((InAddr &)m->victim)));
- if (v && v->team() == myShip->team()) {
- server()->send("destroyed teammate %s (%s)", NetId((InAddr &)m->victim));
- myShip->shipInfo().lost++;
- }
- else {
- server()->send("destroyed %s (%s)", NetId((InAddr &)m->victim));
- myShip->shipInfo().won++;
- }
- }
- }
- if (self(m->victim)) { // I died
- myShip->shipInfo().lost++;
- soundPlay(KilledSound);
- }
- scoreChanged();
- break;
- }
- case SwMessage: {
- static char msg[256], msg2[256];
- const SwMessageMessage* m = (const SwMessageMessage*)&(any->message);
- ShipObject* p = getPlayer(lookupPlayer((InAddr &)m->source));
- sprintf(msg, "%s (%s): %s", p ? p->name() : "???",
- p ? teamName(p->team()) : "???", m->msg);
-
- // put other ship name in if necessary
- if (!NetId((InAddr &)m->target).isAny()) { // about someone in particular
- p = getPlayer(lookupPlayer((InAddr &)m->target));
- sprintf(msg2, msg, p ? p->name() : "???",
- p ? teamName(p->team()) : "???");
- addMessage(msg2);
- }
- else if (m->team != NoTeam) { // about a particular team
- sprintf(msg2, msg, teamName(m->team));
- addMessage(msg2);
- }
- else // general message
- addMessage(msg);
- break;
- }
- case SwWorld:
- // shouldn't happen (handled in open)
- break;
- }
- }
- }
-
- //
- // Server stuff
- //
-
- SwServer::SwServer(const char* serverName)
- {
- // get my host address
- init();
- if (status != NotConnected) return;
-
- // get server host address
- struct hostent* he = gethostbyname(serverName);
- if (!he) {
- cerr << serverName << " not in host database\n";
- status = NoSuchServer;
- }
- else {
- serverNetId = NetId((const char*)(he->h_addr));
- status = NotConnected;
- }
- }
-
- SwServer::SwServer(NetId serverId)
- {
- // get my host address
- init();
- if (status != NotConnected) return;
-
- // store server address (assume it's valid)
- serverNetId = serverId;
- }
-
- SwServer::~SwServer()
- {
- close();
- }
-
- void SwServer::init()
- {
- // get my host name
- char hostname[100];
- if (gethostname(hostname, sizeof(hostname)) < 0) {
- cerr << "can't get my host name\n";
- status = OtherError;
- return;
- }
-
- // get my host address from name
- struct hostent* he = gethostbyname(hostname);
- if (!he) {
- cerr << "my host name (" << hostname << ") not in host database!\n";
- status = OtherError;
- return;
- }
-
- // store my host address
- hostNetId = NetId((const char*)(he->h_addr));
-
- // initialize stuff
- FD_ZERO(&read_set);
- fd = -1;
- status = NotConnected;
- messageOut.length = 0;
- messageOut.type = SwNone;
- messageIn.type = SwNone;
- }
-
- int SwServer::open(const ShipObject* s)
- {
- if (status == Connected) return TRUE; // already connected
- if (status != NotConnected) return FALSE; // not ready to connect
- if (!s) return FALSE; // no ship
-
- // make temporary connection to find port for permanent connection
- struct sockaddr_in addr;
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd == -1) {
- perror("couldn't make get port socket");
- return FALSE;
- }
- addr.sin_family = AF_INET;
- addr.sin_port = SERVERPORT;
- addr.sin_addr = serverNetId;
- if (connect(fd, (const void*)&addr, sizeof(addr)) == -1) {
- perror("couldn't connect get port socket");
- ::close(fd);
- return FALSE;
- }
- addr.sin_family = AF_INET;
- addr.sin_addr = serverNetId;
- int i = read(fd, (void*)&(addr.sin_port), sizeof(addr.sin_port));
- ::close(fd);
- fd = -1;
-
- // see if we're allowed to join
- if (i < sizeof(addr.sin_port)) {
- perror("couldn't get direct port number");
- return FALSE;
- }
- else if (addr.sin_port == 0) {
- fprintf(stderr, "Too many players. Sorry.\n");
- return FALSE;
- }
-
- // open permanent connection to server
- fd = socket(AF_INET, SOCK_STREAM, 0);
- if (fd == -1) {
- perror("couldn't make direct socket");
- return FALSE;
- }
- if (connect(fd, (const void*)&addr, sizeof(addr)) == -1) {
- perror("couldn't connect direct socket");
- ::close(fd);
- fd = -1;
- return FALSE;
- }
- status = Connected;
-
- messageOut.type = SwJoin;
- messageOut.any.join.p.id = s->id();
- messageOut.any.join.p.team = s->team();
- strcpy(messageOut.any.join.p.name, s->name());
- messageOut.any.join.p.shipClass = s->shipClass();
- send();
-
- getWorld();
-
- return TRUE;
- }
-
- void SwServer::close()
- {
- if (status != Connected) return; // not connected
-
- messageOut.type = SwQuit;
- send();
- status = NotConnected;
- }
-
- int SwServer::state() const
- {
- return status;
- }
-
- NetId SwServer::serverId() const
- {
- return serverNetId;
- }
-
- NetId SwServer::hostId() const
- {
- return hostNetId;
- }
-
- void SwServer::getWorld()
- {
- do {
- messageOut.type = SwGetWorld;
- send();
- if (receive(TRUE) == SwWorld) {
- switch (messageIn.any.world.type) {
- case WorldTeam:
- setTeam(messageIn.any.world.info.team);
- break;
- case WorldPlayer: {
- if (NetId(messageIn.any.world.info.player.id) == hostNetId) break;
- ShipObject* n = makeShip(messageIn.any.world.info.player.shipClass,
- messageIn.any.world.info.player.id,
- messageIn.any.world.info.player.team,
- messageIn.any.world.info.player.name);
- n->reset();
- addPlayer(n);
- break;
- }
- }
- }
- } while (type() == SwWorld && messageIn.any.world.count > 0 &&
- status == Connected);
- }
-
- void SwServer::send(const SwAliveMessage& m)
- {
- messageOut.type = SwAlive;
- messageOut.any.alive = m;
- send();
- }
-
- void SwServer::send(const SwHitMessage& m)
- {
- messageOut.type = SwHit;
- messageOut.any.hit = m;
- send();
- }
-
- void SwServer::send(const SwKilledMessage& m)
- {
- messageOut.type = SwKilled;
- messageOut.any.killed = m;
- send();
- }
-
- void SwServer::send(const SwGrabFlagMessage& m)
- {
- messageOut.type = SwGrabFlag;
- messageOut.any.grabFlag = m;
- send();
- }
-
- void SwServer::send(const SwDropFlagMessage& m)
- {
- messageOut.type = SwDropFlag;
- messageOut.any.dropFlag = m;
- send();
- }
-
- void SwServer::send(const SwCaptureFlagMessage& m)
- {
- messageOut.type = SwCaptureFlag;
- messageOut.any.captureFlag = m;
- send();
- }
-
- void SwServer::send(const char* msg)
- {
- messageOut.type = SwMessage;
- strcpy(messageOut.any.message.msg, msg);
- messageOut.any.message.source = hostNetId;
- messageOut.any.message.target = NetId(); // not about anybody
- messageOut.any.message.team = NoTeam; // nor any team
- send();
- }
-
- void SwServer::send(const char* msg, NetId aboutWhom)
- {
- messageOut.type = SwMessage;
- strcpy(messageOut.any.message.msg, msg);
- messageOut.any.message.source = hostNetId;
- messageOut.any.message.target = aboutWhom; // about a player
- messageOut.any.message.team = NoTeam; // not about a team
- send();
- }
-
- void SwServer::send(const char* msg, Team team)
- {
- messageOut.type = SwMessage;
- strcpy(messageOut.any.message.msg, msg);
- messageOut.any.message.source = hostNetId;
- messageOut.any.message.target = NetId(); // not about a player
- messageOut.any.message.team = team; // about a team
- send();
- }
-
- void SwServer::send()
- {
- // send messageOut to server
- if (status != Connected) return; // not ready to send
-
- if (write(fd, (void*)&messageOut, sizeof(messageOut)) < sizeof(messageOut)) {
- ::close(fd);
- fd = -1;
- status = NotConnected;
- messageIn.type = SwNone;
- }
- }
-
- ServerMessageType SwServer::receive(int block)
- {
- if (status == Connected) {
- int nfound;
- FD_SET(fd, &read_set);
- if (block)
- nfound = select(fd + 1, (FD_TYPE*)&read_set, NULL, NULL, NULL);
- else {
- struct timeval timeout;
- timeout.tv_sec = 0; // instant timeout (poll)
- timeout.tv_usec = 0;
- nfound = select(fd + 1, (FD_TYPE*)&read_set, NULL, NULL, &timeout);
- }
- if (nfound > 0) {
- if (read(fd, (void*)&messageIn, sizeof(messageIn)) < sizeof(messageIn)) {
- ::close(fd); // lost connection
- fd = -1;
- status = NotConnected;
- messageIn.type = SwNone;
- }
- }
- else
- messageIn.type = SwNone;
- }
- return messageIn.type;
- }
-
- ServerMessageType SwServer::type() const
- {
- return messageIn.type;
- }
-
- const SwAnyMessage* SwServer::get() const
- {
- return &(messageIn.any);
- }
-